#pragma once

#include <mswin/synchronizable_thread.h>
#include <MyControls/AsyncSequenceView.h>
#include <MyControls/Impl/AsyncSequenceView.inl>
#include "DisplayStyle.h"
#include <MyControls/Property.h>
#include <MyControls/MaskEditor.h>
#include "Paint.h"

class CXComp;
class CXSegment;

struct DisplayDetails {
	CXSegment * pSegment;
	bool CombineAllMasks; ///< false if pSegment points to active or follow segment, true if on topmost (and displayed mask is merged from all segments)
	Size ObjectFrame; ///< equal to current preview frame
	int BackgroundFrame; ///< invalid if no background for the preview frame
};

class CXView : 
	public My::AsyncSequenceView<PaintingKey>,
	public My::EditableObject
{
	typedef My::AsyncSequenceView<PaintingKey> Base;
public:
	CXView(CXComp &);
	virtual ~CXView();
public: //My::AsyncSequenceView<PaintingKey> interface impl.
	virtual PaintingKeySPtr GetPaintingKey(My::Size Frame);
	virtual My::CachedImageSPtr GetPainting(PaintingKeySPtr const & p, icache::nearby nb);
	virtual My::TimeControls * GetTimeControls();
public:
	virtual void SetBackgroundColor(COLORREF c);
	/// Returns display mode that was choosen by the program to workaround absence of
	/// mask in the current frame or background footage, or due to mask editing
	DisplayStyle EffectiveDisplayMode(Size Frame, DisplayDetails * Details = 0);
	DisplayStyle CurrentEffectiveDisplayMode(DisplayDetails * Details = 0);
	/// Show processed segment and frame if in follow mode
	void OnFrameProcessed(CXSegment * pSeg, Size Frame);
	/// Stop showing follow segment
	void OnSegmentProcessed();
public:
	///to call from MaskEditor when mask is painted separately
	void InvalidateMask();
	My::MaskEditor & GetMaskEditor()
		{ return m_MaskEditor; }
	///non-null returned value points to mask in MaskEditor when it's active,
	const BitMask * EditingMask() const
		{ return m_MaskEditor.IsOpen() ? &m_MaskEditor.GetBuffer() : 0; }
public: //EventListener interface
	virtual void ProcessEvent(My::Event &);
public: // Display Mode
	const DisplayStyle & GetDisplayStyle() const
		{ return m_Style; }
	void SetDisplayStyle(const DisplayStyle &);
	/// If RamPreview is true, then composed frames are stored in memory cache;
	/// If memory cache is large enough to contain all frames of work area,
	/// then it's speedups playback; otherwise --- slowdowns.
	bool GetRAMPreview() const
		{ return m_RAMPreview; }
	void SetRAMPreview(bool);
	void SetDisplayType(DisplayType t);
	void SetMaskOnlyDisplayType()
		{ SetDisplayType(MaskOnly); }
	void SetForegroundOnlyDisplayType()
		{ SetDisplayType(ObjectOnly); }
	void SetBackgroundOnlyDisplayType()
		{ SetDisplayType(BackgroundOnly); }
	void SetMattedForegroundDisplayType()
		{ SetDisplayType(MattedObject); }
	void SetCompositionDisplayType()
		{ SetDisplayType(Composition); }
public: // EditableObject
	virtual const char * GetEditCaption() const
		{ return "Display"; }
	virtual const My::PropertyMap & GetProperties() const;
protected:
	DECLARE_MESSAGE_MAP()
	afx_msg void OnRamPreview();
	afx_msg void OnUpdateRamPreview(CCmdUI * pCmdUI);

protected: //SequenceView interface
	virtual COLORREF GetBackgroundColor() const;
	virtual void PaintImageRect(CDC * pDC, CRect const & rClient, CRect const & rImage);
	virtual My::Sequence * GetSequence() const;
	virtual void InvalidateBuffer();
	virtual void OnActivateFollow();
	virtual void OnDeactivateFollow();
	virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);
private: //OffscreenManager interface
	virtual CDC * GetOffscreenDC();

private:
	bool IsEditMaskStyleChanged();

private:
	CXComp &		m_Comp;
	DisplayStyle	m_Style;
	bool			m_RAMPreview;
	//parameters of mask during its editing
	bool			m_EditMaskOnlyMask;
	bool			m_EditMaskInverse;
	ByteColor		m_EditMaskMatte;
	CXSegment *		m_pFollowSegment; ///< Masks of FollowSegment is shown in PlayFollow mode
	My::MaskEditor	m_MaskEditor;
private:
	My::EventSubscription m_CompEvents, m_SegmentSetEvents, m_MaskEditorEvents, m_BackgroundEvents;
private: 
	/// the one and only property
	static My::Property<DisplayStyle> DisplayModeProperty;
};
